package com.yinxing.webapi.code.service.sys;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yinxing.framework.exception.OperationException;
import com.yinxing.framework.exception.YinXingException;
import com.yinxing.framework.mybatis.TemplateService;
import com.yinxing.framework.utils.AppUtils;
import com.yinxing.framework.utils.LongIdUtils;
import com.yinxing.framework.utils.OSSUtils;
import com.yinxing.framework.utils.RandomStringUtils;
import com.yinxing.webapi.code.entity.sys.SysDept;
import com.yinxing.webapi.code.entity.sys.SysUser;
import com.yinxing.webapi.code.mapper.sys.SysUserMapper;
import com.yinxing.webapi.code.viewobje.sys.SysUserVo;
import com.yinxing.webapi.shiro.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class ISysUserService extends TemplateService<SysUser> {

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserroleService sysUserroleService;

    @Autowired
    private ISysRoleService sysRoleService;

    @Autowired
    private ISysPermissionService sysPermissionService;

    @Autowired
    private OSSUtils ossUtils;

    private SysUserMapper getMapper() {
        return (SysUserMapper) baseMapper;
    }

    /**
     * 查询用户信息 LeftJoin机构表(SysDeptName,SysDeptCode)
     */
    public IPage<SysUser> selectUserList(IPage<SysUser> page, Wrapper<SysUser> queryWrapper) {
        return getMapper().selectUserList(page, queryWrapper);
    }

    /**
     * 查询用户信息
     * @param page 分页参数
     * @param params 查询条件
     */
    public IPage<SysUser> selectUserList(IPage<SysUser> page, Map<String,String> params) {
        QueryWrapper<SysUser> qw = new QueryWrapper<>();

        //前台传入QueryParam_作为查询条件
        final String queryParam = "QueryParam_";
        if(params.containsKey(queryParam)) {
            //这里使用or进行多条件组合查询 (name=xx or loginName=xx or phone=xx or email=xx)
            String queryParamValue = params.get(queryParam);
            qw.eq(SysUser.DB_Name_, queryParamValue)
                .or().eq(SysUser.DB_LoginName_, queryParamValue)
                .or().eq(SysUser.DB_Phone_, queryParamValue)
                .or().eq(SysUser.DB_Email_, queryParamValue);
        }

        //前端进行高级查询 根据传入参数构造查询条件
        if(params.containsKey(SysUser.DB_Name_)) {
            //姓名查询
            qw.eq(SysUser.DB_Name_, params.get(SysUser.DB_Name_));
        }
        if(params.containsKey(SysUser.DB_LoginName_)) {
            //登录名查询
            qw.eq(SysUser.DB_LoginName_, params.get(SysUser.DB_LoginName_));
        }
        if(params.containsKey(SysUser.DB_Phone_)) {
            //电话查询
            qw.eq(SysUser.DB_Phone_, params.get(SysUser.DB_Phone_));
        }
        if(params.containsKey(SysUser.DB_Email_)) {
            //邮件查询
            qw.eq(SysUser.DB_Email_, params.get(SysUser.DB_Email_));
        }
        if(params.containsKey(SysUser.DB_Stop_)) {
            //由于连表查询,Stop_字段俩个表都存在，所以这里需要使用sql当中的别名
            qw.eq("user.Stop_", Boolean.valueOf(params.get(SysUser.DB_Stop_)));
        }
        if(params.containsKey("treeNodeId")) {
            //机构ID和机构编码查询
            qw.eq(SysUser.DB_SysDeptId_, params.get("treeNodeId"))
                    .or().like("dept.DeptCode_", params.get("treeNodeCode"));
        }

        //Index倒序排序
        qw.orderByDesc(SysUser.DB_Index_);

        return this.selectUserList(page, qw);
    }

    /**
     * 根据角色ID查询用户数据
     * @param page 分页条件
     * @param params 查询条件 (参数必须包含bindRole="true"|"false"和 sysRoleId)
     *               注意"true"和"false"必须为字符,因为mybatis动态if按字符串处理的.
     */
    public IPage<SysUser> selectUserListByRoleId(IPage<SysUser> page, Map<String, Object> params) {
        AppUtils.notNull(params, "RoleBind_");
        AppUtils.notNull(params, "SysRoleId_");

        IPage<SysUser> iPage = getMapper().selectUserListByRoleId(page, params);
        if(params.get("RoleBind_").equals("true")) {
            //查询已经绑定过角色的用户 需要把RoleBind字段全部设置为true 这样前端ext表格全部为选中状态
            iPage.getRecords().forEach(sysUser -> sysUser.setRoleBind_(true));
        }
        return iPage;
    }

    /**
     * 添加用户
     * @param record 用户数据
     * @param file 用户头像照片
     */
    public void insert(SysUserVo record, MultipartFile file) throws Exception {
        //上传图片
        String fileURL = ossUtils.putMultipartFile(file);

        //检查登录名是否重复
        SysUser oldUser = this.selectByUserLoginName(record.getLoginName_());
        if (oldUser != null) {
            throw new OperationException("登录账户名重复:{" + record.getLoginName_() + "}");
        }

        //开始插入用户数据
        SysUser user = new SysUser();
        BeanUtils.copyProperties(user, record);
        user.setId_(LongIdUtils.DEFAULT.nextId());
        user.setCreateTime_(LocalDateTime.now());
        user.setSalt_(RandomStringUtils.getRandomString(32));
        user.setPassword_(DigestUtils.md5Hex(user.getSalt_() + "123456"));

        //插入图片路径
        if(fileURL != null) {
            user.setPictureUrl_(fileURL);
        }
        super.insert(user);

        //先删除旧角色在绑定新角色
        sysUserroleService.updateUserRoles(user.getId_(), record.getRoles_());
    }

    /**
     * 编辑用户
     * @param record 用户数据
     * @param file 用户头像照片
     */
    public void updateById(SysUserVo record, MultipartFile file) throws Exception {
        //上传图片
        String fileURL = ossUtils.putMultipartFile(file);

        //检查登录名是否重复 (存在相同名称用户 并且用户id与当前用户不一致)
        SysUser oldUser = this.selectByUserLoginName(record.getLoginName_());
        if (oldUser != null && oldUser.getId_().longValue() != record.getId_().longValue()) {
            throw new OperationException("登录账户名重复:{" + record.getLoginName_() + "}");
        }

        //开始插入用户数据
        SysUser user = new SysUser();
        BeanUtils.copyProperties(user, record);
        //插入图片路径
        if(fileURL != null) {
            user.setPictureUrl_(fileURL);
        }
        super.updateById(user);

        //先删除旧角色在绑定新角色
        sysUserroleService.updateUserRoles(user.getId_(), record.getRoles_());
    }

    /**
     * 查询用户
     * @param id 用户id
     */
    public SysUserVo selectById(Long id) {
        SysUser sysUser = baseMapper.selectById(id);
        SysUserVo vo = new SysUserVo();
        try {
            BeanUtils.copyProperties(vo, sysUser);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new YinXingException("属性复制发生错误");
        }
        //查询当前用户绑定的全部角色ID
        Long[] roleIds = sysUserroleService.selectUserRoles(id);
        vo.setRoles_(roleIds);
        return vo;
    }

    /**
     * 查询用户详细信息
     * @param id 用户id
     */
    public SysUserVo selectDetailById(Long id) {
        SysUserVo vo = selectById(id);
        SysDept dept = sysDeptService.selectById(vo.getSysDeptId_());
        if(dept != null) {
            vo.setSysDeptName_(dept.getDeptName_());
            vo.setSysDeptCode_(dept.getDeptCode_());
        }
        return vo;
    }

    /**
     * 根据登录名查询用户
     * @param loginName 登录用户名
     */
    public SysUser selectByUserLoginName(String loginName) {
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.eq(SysUser.DB_LoginName_, loginName);
        return super.selectOne(qw);
    }

    /**
     * 删除用户数据(同时删除用户绑定的角色数据)
     * @param id 用户ID
     */
    public boolean deleteUserAndRoleById(Long id) {
        sysUserroleService.deleteUserAllRoles(id);
        return super.deleteById(id);
    }

    /**
     * 批量删除用户数据(同时删除用户绑定的角色数据)
     * @param id 用户ID
     */
    public void deleteUserAndRoleByIds(Long[] id) {
        if(id != null && id.length > 0) {
            for (int i = 0; i < id.length; i++) {
                this.deleteUserAndRoleById(id[i]);
            }
        }
    }

    /**
     * 批量(绑定|解绑)用户角色
     * @param SysRoleId_ 角色ID
     * @param records 数据集合
     */
    public void updateRoleUsers(long SysRoleId_, List<SysUserVo> records) {
        for (SysUserVo vo: records) {
            if(vo.getRoleBind_() != null && vo.getRoleBind_()) {
                sysUserroleService.insert(vo.getId_(), SysRoleId_);
            } else {
                sysUserroleService.delete(vo.getId_(), SysRoleId_);
            }
        }
    }

    /**
     * 查询用户
     * @param loginName 登录账户
     */
    public SysUser selectByLoginName(String loginName) {
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.eq(SysUser.DB_LoginName_, loginName);
        return selectOne(qw);
    }

    /**
     * 根据用户姓名查询ID集合
     * @param userName 用户姓名
     */
    public List<Long> selectUserIdsByUserName(String userName) {
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.eq(SysUser.DB_Name_, userName);
        return selectList(qw).stream().map(user-> user.getId_()).collect(Collectors.toList());
    }

    /**
     * 构造登录用户信息
     * @param sysUserId 用户ID
     * @param host 登录IP
     */
    public LoginUser createloginUser(long sysUserId, String host) {
        SysUserVo sysUser = this.selectDetailById(sysUserId);
        if(sysUser != null) {
            //创建登录账户信息
            LoginUser loginUser = new LoginUser();
            loginUser.setUserId(sysUser.getId_());
            loginUser.setUsername(sysUser.getName_());
            loginUser.setUserHost(host);
            loginUser.setProfile(sysUser.getPictureUrl_());
            loginUser.setLoginTime(new Date());
            loginUser.setLoginName(sysUser.getLoginName_());
            loginUser.setDeptName(sysUser.getSysDeptName_());

            //角色编码集合
            Set<String> roleCodes = sysRoleService.selectRoleCodesBySysUserId(sysUser.getId_());
            loginUser.setRoles(roleCodes);

            //权限编码集合
            Set<String> userPerms = sysPermissionService.selectPermissionsBySysUserId(sysUser.getId_());
            loginUser.setPermissions(userPerms);

            return loginUser;
        }

        return null;
    }

    /**
     * 修改密码
     * @param userId 用户ID
     * @param passwordNew 密码
     */
    public void passwordReset(long userId, String oldPassword, String passwordNew) {
        SysUser sysUser = super.selectById(userId);
        if(sysUser == null) {
            throw new OperationException("当前用户信息不存在");
        }
        String oldPwdHasd = DigestUtils.md5Hex(sysUser.getSalt_() + oldPassword);
        if(!sysUser.getPassword_().equals(oldPwdHasd)) {
            throw new OperationException("旧密码输入错误");
        }

        sysUser.setPassword_(DigestUtils.md5Hex(sysUser.getSalt_() + passwordNew));
        super.updateById(sysUser);
    }
}